<template>
  <div class="flex flex-col single">
    <header class="main-grid site-header" id='article-entry-header'>
      <div class='entry-header header-bg' :href='headerImage' data-fancybox="images" data-slug="cover" :data-caption="article.articleTitle">
        <img id='header-cover' :src='headerImage' alt='banner' fetchpriority="high">
      </div>
      <div class='entry-title'>
        <h1 v-show='article.articleTitle'>{{ article.articleTitle }}</h1>
        <span class='vcard'>{{ article.categoryName }}</span>
        <span class='tag-list'>
          <template v-for="tag in article.tags" :key="tag.id">
            <a :href='ArticlePath.TAG_PATH +tag.id+"?tagName="+tag.tagName' rel="tag">
              {{ tag.tagName }}
            </a>
          </template>
        </span>
      </div>
      <div class='entry-meta'>
        <div class='entry-meta-left'>
          <div class="author-date">
            <template v-if="article.author">
              <a :href='article.author.website' rel="author">{{ article.author.nickname }}</a>
              <span class='entry-date'>
                <a href='#' rel="bookmark">
                  <time>{{ article.createTime.split('T')[0] }}</time>
                </a>
              </span>
            </template>
          </div>
          <template v-if='article.articleExtraContentVO && article.articleExtraContentVO.weather'>
            <div class="post-weather">
              <i>那时天气</i>
              <span>{{ article.articleExtraContentVO.weather }}</span>
            </div>
          </template>
          <template v-if='article.articleExtraContentVO && article.articleExtraContentVO.mood'>
            <div class="post-mood">
              <i>心情</i>
              <span>{{ article.articleExtraContentVO.mood }}</span>
            </div>
          </template>
          <div class="post-views">
            <i>热度</i>
            <span>{{ article.viewCount }}</span>
          </div>
          <template v-if='article.articleExtraContentVO && article.articleExtraContentVO.location'>
            <div class="post-location">
              <i>地点</i>
              <span>{{ article.articleExtraContentVO.location }}</span>
            </div>
          </template>
          <div class="words-num">
            <i>本文共计</i>
            <span>{{ wordNum }}</span>
          </div>
          <div class="read-time">
            <i>预计阅读</i>
            <span>{{ readTime }}</span>
          </div>
        </div>
        <div class='entry-meta-right'>
          <aside class='entry-summary blur-saturate'>
            <p :title='article.articleAbstract'>{{ article.articleAbstract }}</p>
          </aside>
          <nav class='navigation post-navigation' role="navigation" v-if='article'>
            <a :href='ArticlePath.Path + article.preArticleCard.id' rel="prev" v-show='article.preArticleCard.id'></a>
            <a :href='ArticlePath.Path + article.nextArticleCard.id' rel="next" v-show='article.nextArticleCard.id'></a>
          </nav>
        </div>
      </div>
    </header>
    <div class="content-area" id='article-primary'>
      <main id='main' class="site-main" role="main">
        <article id='post-article'>
          <div class='entry-content'>
            <nav class='table-of-content'>
              <h6>文章目录</h6>
              <div class='no-scrollbar'>

              </div>
            </nav>
            <template v-if="article.articleContent">
                <div class="markdown-body" ref="articleRef" v-html="article.articleContent" />
            </template>
            <div v-else class="bg-ob-deep-800 px-14 py-16 rounded-2xl shadow-xl block min-h-screen">
              <ob-skeleton tag="div" :count="1" height="36px" width="150px" class="mb-6" />
              <br />
              <ob-skeleton tag="div" :count="35" height="16px" width="100px" class="mr-2" />
              <br />
              <br />
              <ob-skeleton tag="div" :count="25" height="16px" width="100px" class="mr-2" />
            </div>
          </div>
          <div class='widget-author-power mt-4' v-show='websiteConfig.isReward === 1 && !isMobile'>
            <button class='reward-btn' @click='rewardShow'>赞赏</button>
            <div class='open-reward'>
              <el-dialog v-model='isRewardShow' top='25vh'>
                <div class='reward-qrcode'>
                  <img class='reward-item' v-show='websiteConfig.weiXinQRCode' :src='websiteConfig.weiXinQRCode' alt='wx-qrcode'>
                  <img class='reward-item' v-show='websiteConfig.alipayQRCode' :src='websiteConfig.alipayQRCode' alt='al-qrcode'>
                </div>
              </el-dialog>
            </div>
          </div>
        </article>
        <AuthorCard :pre-article-card='preArticleCard' :next-article-card='nextArticleCard'>
          <Comment :commentCount='commentCount'/>
        </AuthorCard>
      </main>
    </div>
  </div>
</template>

<script lang="ts">
import {
  computed,
  defineComponent,
  nextTick,
  onUnmounted,
  onMounted,
  reactive,
  ref,
  toRefs,
  provide,
  getCurrentInstance
} from 'vue'
import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { Comment } from '@/components/Comment'
import { ArticleCard } from '@/components/ArticleCard'
import '@/styles/prism-aurora-future.css'
import { useCommonStore } from '@/stores/common'
import { useCommentStore } from '@/stores/comment'
import Sticky from '@/components/Sticky.vue'
import Prism from 'prismjs'
import tocbot from 'tocbot'
import emitter from '@/utils/mitt'
import { v3ImgPreviewFn } from 'v3-img-preview'
import api from '@/api/api'
import markdownToHtml from '@/utils/markdown'
import ObSkeleton from '@/components/LoadingSkeleton/src/Skeleton.vue'
import SvgIcon from '@/components/SvgIcon/index.vue'
import { useAppStore } from '@/stores/app'
import { animateDelayedElements } from '@/utils/animateDelay'
import AuthorCard from '@/components/ArticleCard/src/AuthorCard.vue'
import { ElMessage } from 'element-plus/es'
import { articleService } from '@/service/article.service'
import { setDocumentTitle } from '@/utils/commonUtil'
import { ArticlePath } from '@/models/@types'
export default defineComponent({
  name: 'Article',
  computed: {
    ArticlePath() {
      return ArticlePath
    }
  },
  components: { AuthorCard, SvgIcon, ObSkeleton, Comment, ArticleCard, Sticky, Navigator },
  setup() {
    const proxy: any = getCurrentInstance()?.appContext.config.globalProperties
    const commonStore = useCommonStore()
    const commentStore = useCommentStore()
    const appStore = useAppStore()
    const route = useRoute()
    const router = useRouter()
    const { t } = useI18n()
    const loading = ref(true)
    const articleRef = ref()
    const reactiveData = reactive({
      articleId: '' as any,
      article: '' as any,
      wordNum: '' as any,
      readTime: '' as any,
      comments: [] as any,
      images: [] as any,
      preArticleCard: '' as any,
      nextArticleCard: '' as any,
      haveMore: false as any,
      isReload: false as any,
      commentCount: 0 as number,
      isRewardShow: false
    })
    const pageInfo = reactive({
      current: 1,
      size: 7
    })
    commentStore.type = 1
    onMounted(() => {
      reactiveData.articleId = route.params.articleId
      toPageTop()
      fetchArticle()
      fetchComments()
      nextTick(()=>{
        animateDelayedElements('.entry-meta-left', 'div', 0.7)
      })
    })
    onUnmounted(() => {
      commonStore.resetHeaderImage()
      reactiveData.article = ''
      tocbot.destroy()
      articleService.RemovePostBodyClassList()
    })
    onBeforeRouteUpdate((to) => {
      reactiveData.article = ''
      reactiveData.readTime = ''
      reactiveData.wordNum = ''
      reactiveData.comments = []
      reactiveData.images = []
      reactiveData.preArticleCard = ''
      reactiveData.nextArticleCard = ''
      reactiveData.articleId = to.params.articleId
      pageInfo.current = 1
      reactiveData.isReload = true
      toPageTop()
      fetchArticle()
      fetchComments()
    })
    provide(
      'comments',
      computed(() => reactiveData.comments)
    )
    provide(
      'haveMore',
      computed(() => reactiveData.haveMore)
    )
    emitter.on('articleFetchComment', () => {
      pageInfo.current = 1
      reactiveData.isReload = true
      fetchComments()
    })
    emitter.on('articleFetchReplies', (index) => {
      fetchReplies(index)
    })

    emitter.on('articleLoadMore', () => {
      fetchComments()
    })
    const handlePreview = (index: any) => {
      v3ImgPreviewFn({ images: reactiveData.images, index: reactiveData.images.indexOf(index) })
    }
    const initTocbot = () => {
      let nodes = articleRef.value.children
      if (nodes.length) {
        for (let i = 0; i < nodes.length; i++) {
          let node = nodes[i]
          let reg = /^H[1-4]{1}$/
          if (reg.exec(node.tagName)) {
            node.id = i
          }
        }
      }
      tocbot.init({
        tocSelector: '.no-scrollbar',
        contentSelector: '.markdown-body',
        headingSelector: 'h1, h2, h3, h4',
        hasInnerContainers: true,
        onClick: function (e) {
          e.preventDefault()
        },
        scrollSmooth: true
      })
      const imgs = articleRef.value.getElementsByTagName('img')
      for (var i = 0; i < imgs.length; i++) {
        reactiveData.images.push(imgs[i].src)
        imgs[i].addEventListener('click', function (e: any) {
          handlePreview(e.target.currentSrc)
        })
      }
    }
    const fetchArticle = () => {
      loading.value = true
      api.getArticeById(reactiveData.articleId).then(({ data }) => {
        if (data.code === 52003) {
          ElMessage({ message: '文章密码认证未通过', type: 'error' })
          router.push({ path: '/出错啦' })
          return
        }
        if (data.data === null) {
          router.push({ path: '/出错啦' })
          return
        }
        articleService.postType(data.data.postType)
        commonStore.setHeaderImage(data.data.articleCover)
        new Promise((resolve) => {
          data.data.articleContent = markdownToHtml(data.data.articleContent)
          resolve(data.data)
        }).then((article: any) => {
          reactiveData.article = article
          setDocumentTitle(article.articleTitle)
          reactiveData.wordNum = Math.round(deleteHTMLTag(article.articleContent).length) + '字'
          reactiveData.readTime = Math.round(deleteHTMLTag(article.articleContent).length / 400) + '分'
          loading.value = false
          nextTick(() => {
            Prism.highlightAll()
            initTocbot()
          })
        })
        new Promise((resolve) => {
          data.data.preArticleCard.articleContent = data.data.preArticleCard.articleAbstract
          resolve(data.data.preArticleCard)
        }).then((preArticleCard: any) => {
          reactiveData.preArticleCard = preArticleCard
        })
        new Promise((resolve) => {
          data.data.nextArticleCard.articleContent = data.data.nextArticleCard.articleAbstract
          resolve(data.data.nextArticleCard)
        }).then((nextArticleCard) => {
          reactiveData.nextArticleCard = nextArticleCard
        })
      })
    }
    const fetchComments = () => {
      const params = {
        type: 1,
        topicId: reactiveData.articleId,
        current: pageInfo.current,
        size: pageInfo.size
      }
      api.getComments(params).then(({ data }) => {
        reactiveData.commentCount=data.data.count
        if (reactiveData.isReload) {
          reactiveData.comments = data.data.records
          reactiveData.isReload = false
        } else if(data.data.records){
          reactiveData.comments.push(...data.data.records)
        }
        reactiveData.haveMore = data.data.count > reactiveData.comments.length;
        pageInfo.current++
      })
    }
    const fetchReplies = (index: any) => {
      api.getRepliesByCommentId(reactiveData.comments[index].id).then(({ data }) => {
        reactiveData.comments[index].replyDTOs = data.data
      })
    }
    const handleAuthorClick = (link: string) => {
      if (link === '') link = window.location.href
      window.location.href = link
    }
    const toPageTop = () => {
      window.scrollTo({
        top: 0
      })
    }
    const deleteHTMLTag = (content: any) => {
      return content
        .replace(/<\/?[^>]*>/g, '')
        .replace(/[|]*\n/, '')
        .replace(/&npsp;/gi, '')
    }
    const rewardShow = () => {
      return reactiveData.isRewardShow =true
    }
    return {
      rewardShow,
      articleRef,
      ...toRefs(reactiveData),
      isMobile: computed(() => commonStore.isMobile),
      handleAuthorClick,
      loading,
      t,
      websiteConfig: computed(() => {
        return appStore.websiteConfig
      }),
      // post-header-img
      headerImage: computed(() => {
        return commonStore.headerImage ? commonStore.headerImage : require('@/assets/default-cover.jpg')
      })
    }
  }
})
</script>
<style lang="scss">

.table-of-content:hover {
  opacity: 1;
}
.single-format-video .table-of-content{
  display: none;
}
.table-of-content h6::before {
  content: "\e652" !important;
  margin: 0 0.5em 0 0;
  font-family: 'iconfont';
  font-weight: 400;
}
.no-scrollbar ol {
  list-style: none;
  margin: -0.5rem 0;
  max-height: 100%;
  font-size: var(--font-size-medium);
  counter-reset: section;
  overflow: clip scroll;
  padding: 1rem 0;
  -webkit-mask: linear-gradient(180deg, #00000000, #000) no-repeat 0 0 / 100% 1rem, linear-gradient(180deg, #000, #000) no-repeat center / 100% calc(100% - 2rem), linear-gradient(180deg, #000, #00000000) no-repeat 100% 100% / 100% 1rem;
}
.no-scrollbar li {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  transform-origin: center left;
  transition: .5s;
}
.no-scrollbar .is-active-li a{
  color: rgb(var(--color-rgb));
}
.table-of-content:hover ol li {
  opacity: .75;
}
.table-of-content:hover ol li:hover {
  opacity: 1;
  scale: 1.1;
}
.toc-list-item ol{
  counter-reset: subsection;
}
.toc-list-item a::before {
  font-variant-numeric: tabular-nums;
  counter-increment: section;
  content: "" counter(section) ". ";
}
.toc-list-item ol li{
  margin: 0 0 0 1.5em;
  font-size: 0.75rem;
}
.toc-list-item ol li a::before{
  font-variant-numeric: tabular-nums;
  counter-increment: subsection;
  content: counter(section) "." counter(subsection) " ";
}
.toc-list-item a{
  opacity: 1;
}
.single .entry-header {
  border-radius: 0;
  width: 100%;
  height: 100%;
  position: fixed;
  animation: opacity 1s ease-in-out backwards;
  top: 0;
  left: 0;
}
#article-entry-header {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 100vh;
  padding-block: var(--gap-divs);
}
.single-format-video .words-num,.single-format-video .read-time{
  display: none;
}
body:is(.single-format-video, .single-format-gallery) .entry-header {
  filter: blur(20px) brightness(.3) !important;
  animation: opacity 1s ease-in-out backwards;
  position: fixed;
  inset: -40px;
  width: calc(100% + 80px);
  height: calc(100% + 80px);
  z-index: 0;
}
.single .entry-title h1 {
  line-height: 1.75;
  width: min(20em, 90%);
  margin: 0 0 0.5em 0;
  font-size: 1.875rem;
}
body:is(.single-format-video, .single-format-image) .entry-title h1 {
  width: auto;
}
.single .entry-header img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: 2s;
  animation: opacity 1s;
}
.single .entry-title{
  position: relative;
  animation: opacity .75s var(--animation-in) .7s 1 backwards;
  z-index: 2;
  font-family: var(--top-font-family);
}
.single .entry-title,.single .entry-meta{
  color: rgb(255 255 255 / 90%);
  text-shadow: var(--text-shadow);
  padding-inline: var(--edge-lr);
}
.single .entry-title{
  margin-bottom: 1.5rem;
}
.single .entry-meta{
  cursor: pointer;
}
.author-date a{
  opacity: 1;
}
.vcard {
  margin: 0 1em 0 0;
}
.tag-list a{
  opacity: 1;
  margin-right: 0.5rem;
}
.tag-list a::before {
  font-family: 'iconfont';
  content: "\e659";
  margin: 0;
}
.single .entry-meta > * span::before,.vcard::before{
  font-family: 'iconfont';
  margin: 0 0.25em 0 0;
}
.vcard::before{
  content: "\e652";
}
.post-weather span::before {
  content: "\e628";
}
.post-mood span::before {
  content: "\e613";
}
.post-views span::before {
  content: "\e68e";
}
.post-location span::before {
  content: "\e63d";
}
.words-num span::before {
  content: "\e693";
}
.read-time span::before {
  content: "\e996";
}
.entry-meta-left i{
  font-style: normal;
}
.entry-meta-right {
  align-items: stretch;
}
.entry-summary {
  max-width: 22.5rem;
  text-align: justify;
  font-size: inherit;
  display: flex;
  align-items: center;
  z-index: 2;
  color: rgb(255 255 255 / 90%);
  text-shadow: var(--text-shadow);
}
.entry-summary::before {
  content: '\e644';
  font-family: 'iconfont';
  font-size: 1.5rem;
  opacity: .5;
  position: absolute;
  top: -1rem;
  left: 0.5rem;
}
.entry-summary p {
  margin: 0;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: auto;
  font-family: var(--top-font-family);
}
.entry-meta-right > *:nth-child(1) {
  animation-delay: .9s;
}
.post-navigation {
  animation: var(--animation-ot);
  animation-delay: .7s;
  display: grid;
  gap: var(--gap-span);
  grid: auto / 1fr;
  z-index: 2;
}
.post-navigation a {
  display: flex;
  align-items: center;
  padding: 0.5rem;
  background: rgb(255 255 255 / 5%);
  box-shadow: var(--box-shadow);
  border-radius: var(--radius);
  opacity: 1;
}

#article-entry-title{
  text-align: center;
}
.content-area{
  position: relative;
  background: var(--h-bg);
  border-radius: var(--radius) var(--radius) 0 0;
  padding-bottom: var(--gap-area);
  padding-top: var(--gap-area);
  z-index: 2;
  animation: var(--animation-ot);
  animation-delay: .7s;
  width: 100%;
}
body:is(.single-format-video) :is(.content-area, .aside-area) {
  padding-top: var(--gap-divs);
  border: 0;
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.entry-content{
  width: min(var(--content-size, 60rem),100%);
  margin-inline: auto;
  letter-spacing: .01em;
  line-height: 2.5;
  text-align: justify;
  word-break: break-all;
  overflow-wrap: anywhere;
  counter-reset: section;
  font-family: var(--top-font-family);
}

pvideo {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  justify-content: center;
}
pvideo iframe {
  width: 100%;
  height: 100%;
}
.single-format-video .markdown-body > *:not(a),.single-format-video .aside-navigation a{
  color: white;
}
@media (min-width: 1153px) {
  .single-format-video #article-entry-header {
    height: 100vh;
    width: 35%;
    margin: var(--edge-tb) 0 0 0;
    justify-content: center;
    padding-inline: var(--edge-lr);
  }
  .single-format-video .entry-meta {
    justify-content: flex-start;
  }
  .single-format-video .content-area {
    position: static;
    animation: opacity .75s var(--animation-in) 1 1s backwards;
  }
  .single-format-video pvideo:first-of-type {
    width: calc(60% - var(--edge-lr)*3);
    position: absolute;
    top: 30%;
    transform: translateY(-65%);
    aspect-ratio: 16 / 9;
    right: 5rem;
    height: auto;
    padding: 0;
    z-index: 2;
  }
}
</style>
